package cn.com.yto56.coresystem.business.msg.mc.app;

import cn.com.yto56.coresystem.business.msg.mc.biz.impl.MsgChannelManager;
import cn.com.yto56.coresystem.business.msg.mc.util.MsgResult;
import cn.com.yto56.coresystem.common.msg.util.base.StringUtils;
import cn.com.yto56.coresystem.common.msg.util.domain.AppResult;
import cn.com.yto56.coresystem.common.msg.util.io.AppConfigurationUtil;
import cn.com.yto56.coresystem.msg.client.YtoMsgServiceClient;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by wangrui on 2017/4/13.
 */
public class MsgServerHandler extends ChannelInboundHandlerAdapter {
    private static final Logger logger = LoggerFactory.getLogger(MsgServerHandler.class);
    //spring管理
    private ApplicationContext applicationContext;
    //SOA消息服务
    private static YtoMsgServiceClient ytoMsgServiceClient;
    //线程管理工具
    private MsgChannelManager msgChannelManager;


    /**
     * 初始化application
     *
     * @param applicationContext
     */
    public MsgServerHandler(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        String url = AppConfigurationUtil.getPropertyValue("msg.soa.url");
        String REQUEST_TYPE = AppConfigurationUtil.getPropertyValue("msg.soa.type");
        try {
            ytoMsgServiceClient = new YtoMsgServiceClient(url, REQUEST_TYPE);
        } catch (MalformedURLException e) {
            logger.error("SOA客户端初始化失败", e);
        }
        this.msgChannelManager = (MsgChannelManager) applicationContext.getBean("msgChannelManager");
    }


    /*
     * channelAction
     *
     * channel 通道
     * action  活跃的
     *
     * 当客户端主动链接服务端的链接后，这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
     *
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端地址" + ctx.channel().remoteAddress());
        String clientId = "mc_temp_" + String.valueOf(new Date().getTime());
        msgChannelManager.addChannel(clientId, ctx.channel());
    }


/*
     * channelRead
	 *
	 * channel 通道
	 * Read    读
	 *
	 * 简而言之就是从通道中读取数据，也就是服务端接收客户端发来的数据
	 * 但是这个数据在不进行解码时它是ByteBuf类型的后面例子我们在介绍
	 *
	 */

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //请求信息
        String requestJson = "";
        //返回信息
        String responseJson = "";
        //缓存区数据对象
        ByteBuf result = (ByteBuf) msg;
        byte[] resultByte = new byte[result.readableBytes()];
        result.readBytes(resultByte);
        if (result != null) {
            result.release();
        }
        String paramJson = new String(resultByte, "UTF-8");
        //拆分json
        MsgResult msgResult = new MsgResult();
        msgResult.setParamJson(paramJson);
        String interfaceName = msgResult.getInterfaceName();
        if (StringUtils.isNotBlank(interfaceName)) {
            if (interfaceName.equals("ytoMsgService.checkUser")) {
                //校验用户接口，首次建立连接调用
                String yto_msg_appId = msgResult.getYto_msg_appId();
                Map requestMap = (Map) msgResult.getDatas();
                String yto_msg_userId = (String) requestMap.get("yto_msg_userId");
                ytoMsgServiceClient.bindAppId(yto_msg_appId);
                AppResult appResult = ytoMsgServiceClient.checkUser(yto_msg_userId);
                if (appResult.getResultFlag()) {
                    //更新用户主键
                    String yto_msg_sysInfo_id = (String) ((Map) appResult.getDatas()).get("yto_msg_sysInfo_id");
                    msgChannelManager.updateByChannel(yto_msg_sysInfo_id + "|" + yto_msg_userId + "|" + yto_msg_appId, ctx.channel());
                }
                //返回信息
                responseJson = msgResult.getResponseJson("ytoMsgService.checkUser", appResult);
            } else if (interfaceName.equals("ytoMsgService.updateMsgListState")) {
                //获取客户端返回的消息处理记录
                String yto_msg_appId = msgResult.getYto_msg_appId();
                Map requestMap = (Map) msgResult.getDatas();
                List<Map> msgLists = (List<Map>) requestMap.get("yto_msg_msgList");
                ytoMsgServiceClient.bindAppId(yto_msg_appId);
                ytoMsgServiceClient.updateMsgListState(msgLists);
            } else if (interfaceName.equals("ytoMsgService.getCurrentMSG")) {
                //客户端主动请求消息
            } else {
                sendErrorMsg(ctx.channel(), "接口[" + interfaceName + "]不存在，请检查接口是否书写正确");
            }

            //推送消息
            if (StringUtils.isNotBlank(responseJson)) {
                ByteBuf buf = Unpooled.buffer(responseJson.getBytes("UTF-8").length);
                buf.writeBytes(responseJson.getBytes("UTF-8"));
                ctx.channel().writeAndFlush(buf);
            } else {
                sendErrorMsg(ctx.channel(), "服务器端处理失败");
            }
        } else {
            sendErrorMsg(ctx.channel(), "请求数据有误，请检查数据格式是否正确，请求的数据为:" + paramJson);
        }

    }

    /*
     * channelReadComplete
     *
     * channel  通道
     * Read     读取
     * Complete 完成
     *
     * 在通道读取完成后会在这个方法里通知，对应可以做刷新操作
     * ctx.flush()
     *
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.channel().flush();
    }

    /*
     * channelInactive
     *
     * channel 	通道
     * Inactive 不活跃的
     *
     * 这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
     *
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        msgChannelManager.removeByChannel(ctx.channel());
    }


    /**
     * IDLE 事件
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            String hearStr = "USERSTATE";
            ByteBuf buf = Unpooled.buffer(hearStr.getBytes("UTF-8").length);
            buf.writeBytes(hearStr.getBytes("UTF-8"));
            if (e.state() == IdleState.READER_IDLE) {
                System.out.println("[发送心跳探测消息READER_IDLE][" + hearStr + "]");
                ctx.channel().writeAndFlush(buf);
            } else if (e.state() == IdleState.WRITER_IDLE) {
                System.out.println("[发送心跳探测消息WRITER_IDLE][" + hearStr + "]");
                ctx.channel().writeAndFlush(buf);
            } else if (e.state() == IdleState.ALL_IDLE) {
                System.out.println("[定时向客户端发送数据]");
                //服务器主动向客户端下发消息, 添加缓存机制
            }

        }
    }

    /**
     * 发送错误提示消息给客户端
     *
     * @param channel
     * @param msg
     */
    public void sendErrorMsg(Channel channel, String msg) throws UnsupportedEncodingException {
        if (channel != null) {
            MsgResult msgResult = new MsgResult();
            String responseJson = msgResult.getResponseJson("ytoMsgService.prompt", false, msg, null);
            ByteBuf buf = Unpooled.buffer(responseJson.getBytes("UTF-8").length);
            buf.writeBytes(responseJson.getBytes("UTF-8"));
            channel.writeAndFlush(buf);
        }
    }
}
